home *** CD-ROM | disk | FTP | other *** search
/ The Very Best of Atari Inside / The Very Best of Atari Inside 1.iso / mint / mntlb20 / lib / strtol.c < prev    next >
C/C++ Source or Header  |  1992-02-07  |  3KB  |  126 lines

  1. /* original from norbert schelenkar's stdio */
  2. /* eff hacks    ++jrb */
  3. /* conversion to ansi spec -- mj */
  4. /* 
  5.  * Base can be anything between 2 and 36 or 0.
  6.  * If not NULL then resulting *endptr points to the first
  7.  * non-accepted character.
  8.  */
  9.  
  10. /* Can't get it to work right under Sozobon. (Just overflow checking.) */
  11.  
  12. #include <ctype.h>
  13. #include <errno.h>
  14. #include <limits.h>
  15. #include <stddef.h>
  16. #include <stdlib.h>
  17.  
  18. /* macro to avoid most frequent long muls on a lowly 68k */
  19. #define _BASEMUL(B, SH, X) \
  20.     ((0 != SH) ? \
  21.        ((10 == (B)) ? ((((X) << (SH)) + (X)) << 1) : ((X) << (SH))) : \
  22.        ((X) * (B))) 
  23.  
  24. long int strtol(nptr, endptr, base)
  25. register const char *nptr;
  26. char **endptr;
  27. int base;
  28. {
  29.   register short c;
  30.   long result = 0L;
  31. #ifndef __SOZOBON__
  32.   long limit;
  33. #endif
  34.   short negative = 0;
  35.   short overflow = -2;    /* if this stays negative then
  36.               no conversion was performed */
  37.   short digit;
  38.   int shift;
  39.  
  40.   if (endptr != NULL)
  41.       *endptr = (char *)nptr;
  42.  
  43.   while ((c = *nptr) && isspace(c))    /* skip leading white space */
  44.     nptr++;
  45.   if ((c = *nptr) == '+' || c == '-') {    /* handle signs */
  46.     negative = (c == '-');
  47.     nptr++;
  48.   }
  49.   if (base == 0) {            /* determine base if unknown */
  50.     if (*nptr == '0') {
  51.         base = 8;
  52.         nptr++;
  53.         if ((c = *nptr) == 'x' || c == 'X') {
  54.             base += base;
  55.             nptr++;
  56.         }
  57.     }
  58.     else
  59.         base = 10;
  60.   }
  61.   else
  62.   if (base == 16 && *nptr == '0') {    /* discard 0x/0X prefix if hex */
  63.     nptr++;
  64.     if ((c = *nptr == 'x') || c == 'X')
  65.         nptr++;
  66.   }
  67.   if (base < 2 || base > 36)
  68.       return result;
  69.  
  70.   /* be careful with a preprocessor and signs!! */
  71. #ifndef __SOZOBON__
  72.   limit = (long)LONG_MIN/(long)base;         /* ensure no overflow */
  73. #endif
  74.   shift = 0;
  75.   switch (base) {
  76.       case 32: shift++;
  77.       case 16: shift++;
  78.       case 8: shift++;
  79.       case 4: case 10: shift++;
  80.       case 2: shift++;
  81.       default:;
  82.   }
  83.   
  84.   nptr--;                /* convert the number */
  85.   while (c = *++nptr) {
  86.     if (isdigit(c))
  87.         digit = c - '0';
  88.     else
  89.         digit = c - (isupper(c) ? 'A' : 'a') + 10;
  90.     if (digit < 0 || digit >= base)
  91.         break;
  92. #ifdef __SOZOBON__
  93.     result = _BASEMUL(base, shift, result) - digit;
  94. #else
  95.     if (0 == (overflow &= 1)) {    /* valid digit
  96.                        - some conversion performed */
  97.         if ((result < limit) ||
  98.         (digit >
  99.          ((result = _BASEMUL(base, shift, result)) - LONG_MIN))) {
  100.         result = LONG_MIN;
  101.         overflow = 1;
  102.         
  103.         }
  104.         else 
  105.         result -= digit;
  106.     }
  107. #endif /* __SOZOBON__ */
  108.   }
  109.  
  110.   if (!negative) {
  111.       if (LONG_MIN == result) {
  112.       result += 1;        /* this is -(LONG_MAX) */
  113.       overflow = 1;        /* we may get LONG_MIN without overflow */
  114.       }
  115.       result = 0L - result;
  116.   }
  117.   
  118.   if (overflow > 0) {
  119.     errno = ERANGE;
  120.   }
  121.  
  122.   if ((endptr != NULL) && (overflow >= 0))     /* move *endptr if some */
  123.       *endptr = (char *) nptr;                  /* digits were accepted */
  124.   return result;
  125. }
  126.